/**
 * @file    hal_uart.c
 * @author  Azolla (1228449928@qq.com)
 * @brief   led contorl PWM
 * @version 0.1
 * @date    2023-08-01
 * 
 * @copyright Copyright (c) 2023
 * */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "sdkconfig.h"

#include "hal_config.h"

#include "hal_uart.h"
 
// #define TAG  "hal_uart"
 
// Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin
#define UART_READ_TOUT   (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks
 
typedef struct {
    uart_port_t port;
    uint16_t size;
} hal_uart_task_t;
 
static uart_recv_callback_t uart_recv_callback_func[UART_NUM_MAX] = { NULL };  // 注册3个串口接收回调函数
static hal_uart_task_t uart_task_arg[UART_NUM_MAX] = { 0 };   // 串口接收任务用到的参数

static void uart_read_task(void *arg);

// UART订阅接收消息服务回调函数
void hal_uart_recv_register_callback(uart_port_t port, uint16_t size, uart_recv_callback_t cb_func)
{
    if (cb_func == NULL) return;
    // Creating UART Recvice task
    uart_task_arg[port].port = port;
    uart_task_arg[port].size = size;
    uart_recv_callback_func[port] = cb_func;  // 注册接收回调函数
    xTaskCreatePinnedToCore(uart_read_task, "uart_read_task", 6 * 1024, (void *)&uart_task_arg[port].port, 8, NULL, APP_CPU_NUM);   
}

void hal_uart_recv_callback(uart_port_t port, uint8_t *data, uint16_t len)
{
    uart_recv_callback_func[port](port, data, len);
}

static void hal_uart_write_bytes(const uart_port_t port, const uint8_t *data, uint16_t len)
{
    if (uart_write_bytes(port, data, len) != len) {
        // add your code to handle sending failure here
    } else {
        ESP_ERROR_CHECK( uart_wait_tx_done(port, 100) );  
    }
}

void hal_uart_write(const uart_port_t port, const uint8_t *data, uint16_t len)
{
#ifdef TAG
    char uart_tag[32];
    sprintf(uart_tag, "uart_write[%d]", port);
    esp_log_buffer_hex(uart_tag, data, len);
#endif
    hal_uart_write_bytes(port, data, len);
}

static void uart_read_task(void *arg)
{
    hal_uart_task_t uart_arg;
    uart_arg.port = *((uart_port_t*)arg);
    uart_arg.size = uart_task_arg[uart_arg.port].size;
    if (uart_arg.port >= UART_NUM_MAX) vTaskDelete(NULL);
#ifdef TAG
    ESP_LOGI(TAG, "<uart_read_task>, UART[%d]->buff_size = %d \r\n", uart_arg.port, uart_arg.size);
#endif 
    // Allocate buffers for UART
    // uint8_t *data = malloc(uart_arg.size);
    uint8_t *data = heap_caps_malloc(uart_arg.size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
    while ( true ) {
        // Read data from UART
        int len = uart_read_bytes(uart_arg.port, data, uart_arg.size, 100 / portTICK_PERIOD_MS);
        if (len > 0) {
            data[len] = '\0';
            // ESP_LOGI(TAG, "uart_callback[%d]: %.*s | %d", uart_arg.port, len, data, len);
            // esp_log_buffer_hex(TAG, data, len);
            uart_recv_callback_func[uart_arg.port](uart_arg.port, data, len);
        }
    }
}


void hal_uart_driver_install(hal_uart_config_t uart)
{
    if (uart.buff_size < 128) uart.buff_size = 128;  
    // Install UART driver (we don't need an event queue here)
    // In this example we don't even use a buffer for sending data.
    ESP_ERROR_CHECK(uart_driver_install(uart.port, uart.buff_size * 2, 0, 0, NULL, 0));
    // Configure UART parameters
    ESP_ERROR_CHECK(uart_param_config(uart.port, &uart.config));
    // Set UART pins as per KConfig settings
    ESP_ERROR_CHECK(uart_set_pin(uart.port, uart.txd_pin, uart.rxd_pin, uart.rts_pin, uart.cts_pin));
    // Set RS485 half duplex mode
    ESP_ERROR_CHECK(uart_set_mode(uart.port, uart.mode));
    // Set read timeout of UART TOUT feature
    ESP_ERROR_CHECK(uart_set_rx_timeout(uart.port, UART_READ_TOUT));
}

void hal_uart_init(uart_recv_callback_t cb_func)
{
    hal_uart_config_t uart = HAL_UART_CONFIG_DEFAULT(38, 39, UART_NUM_1, 115200);
    hal_uart_driver_install(uart);
    hal_uart_recv_register_callback(uart.port, uart.buff_size, cb_func);  // 注册接收回调函数！
#if 1  // debug.
    hal_uart_config_t uart0 = HAL_UART_CONFIG_DEFAULT(43, 44, UART_NUM_0, 115200);
    hal_uart_driver_install(uart0);
    hal_uart_recv_register_callback(uart0.port, uart0.buff_size, cb_func);  // 注册接收回调函数！
#endif
}

